/*
* ========== Copyright Header Begin ==========================================
* 
* OpenSPARC T1 Processor File: xicache.c
* Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* 
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* 
* The above named program is distributed in the hope that it will be 
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
* 
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* 
* ========== Copyright Header End ============================================
*/
/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
#pragma ident	"@(#)xicache.c	1.14	06/05/05 SMI"

	/*
	 * Support routines for the execution instruction cache
	 */

#include <assert.h>

#include "basics.h"
#include "allocate.h"
#include "simcore.h"
#include "config.h"
#include "xicache.h"


	/*
	 * XI cache consists of two components ...
	 * trans_cache:
	 * A translation cache to speed I tlb and simulated I cache operation
	 * instn_cache:
	 * A cache of pre-decoded instructions - so we can handle snooping of
	 * writes to instruction memory.
	 */

xicache_t * xicache_alloc()
{
	xicache_t * xcp;
	int i,j;

	xcp = Xcalloc(1, xicache_t);

	for (j=0; j<XICACHE_NUM_LINES; j++) {
		xicache_line_t * lp;

		lp = &(xcp->line[j]);
		lp->tag = XC_INVALID_TAG;
		lp->memoryoffset = 0;
	}
	for (i=0; i<XICACHE_NUM_INSTRS; i++) {
		xcp->instn[i].exec_funcp = NULL;
		xcp->instn[i].rawi = XICACHE_DEAD_INSTN;
	}

	return xcp;
}



	/*
	 * This flush resets the decode for all instructions.
	 *
	 * exec_loop does this one a per-instruction basis by
	 * comparing rawi to memory.
	 */

void xicache_instn_flush(simcpu_t * sp)
{
	int i;
	xicache_t * xcp;
	void (*decodemep)(simcpu_t *, xicache_instn_t *);

	xcp = sp->xicachep;
	decodemep = sp->decodemep;

	for (i=0; i<XICACHE_NUM_INSTRS; i++) {
		xcp->instn[i].exec_funcp = decodemep;
		xcp->instn[i].rawi = XICACHE_DEAD_INSTN;
	}

	set_attention(sp);
}


	/*
	 * This flush merely forces a miss in the XI-cache by
	 * invalidating the translation tags.
	 */

void xicache_trans_flush(simcpu_t * sp)
{
	int j;
	xicache_t * xcp;

	xcp = sp->xicachep;

	for (j=0; j<XICACHE_NUM_LINES; j++) {
		xicache_line_t * lp;

		lp = &(xcp->line[j]);
		lp->tag = XC_INVALID_TAG;
	}

	set_attention(sp);
}



	/*
	 * XI-cache full flush ...
	 * invalidate the tags, and the contents of the
	 * decoded instructions.
	 */

void xicache_full_flush(simcpu_t * sp)
{
	int i;
	xicache_t * xcp;
	void (*decodemep)(simcpu_t *, xicache_instn_t *);

	xcp = sp->xicachep;
	decodemep = sp->decodemep;

	for (i=0; i<XICACHE_NUM_LINES; i++) {
		xicache_line_t * lp;

		lp = &(xcp->line[i]);
		lp->tag = XC_INVALID_TAG;
		lp->memoryoffset = 0;
	}
	for (i=0; i<XICACHE_NUM_INSTRS; i++) {
		xcp->instn[i].exec_funcp = decodemep;
		xcp->instn[i].rawi = XICACHE_DEAD_INSTN;
	}

	set_attention(sp);
}



	/*
	 * If a translated instruction is in the XI cache, then flush the whole line
	 * ... this may become implementation dependent depending on whether or not
	 * we want the XI cache to be over loaded for icache simulations, but for the
	 * time being we flush the whole line .. because in reality the I$ would have to
	 * go re-read the line from the L2 anyway in a split I/D implementation. 
	 */

void xicache_flush_line(simcpu_t * sp, tvaddr_t va)
{
	tvaddr_t tag;
	xicache_t * xcp;
	xicache_line_t * lp;

	xcp = sp->xicachep;
	tag = va & XICACHE_TAG_MASK;

	lp = &(xcp->line[(tag >> XICACHE_LINE_SIZE_BITS)&XICACHE_LINE_MASK]);

	if (lp->tag == tag) {
		lp->tag = XC_INVALID_TAG;

		set_attention(sp);
	}
}


	/*
	 * This function is used to clobber the instruction decodes
	 * in the xicache that correspond to a single xi-cache line
	 * that is being displaced.
	 * As the cache is direct-mapped you may pass in a full VA
	 * or a index.
	 * No tag check is done because we are explicitly clobbering the
	 * line to avoid instruction aliasing ..
	 */

void xicache_clobber_line_decodes(simcpu_t * sp, tvaddr_t tagva)
{
	tvaddr_t tag;
	xicache_t * xcp;
	xicache_instn_t * ip;
	int idx, i;
	void (*decodemep)(simcpu_t *, xicache_instn_t *);

	xcp = sp->xicachep;
	tag = tagva & XICACHE_TAG_PURE_MASK;
	idx = (tag >> XICACHE_INSTR_SHIFT_BITS) & XICACHE_NUM_INSTR_MASK;
	decodemep = sp->decodemep;

	ip = &(xcp->instn[idx]);
	for (i=0; i<(XICACHE_LINE_SIZE >> XICACHE_INSTR_SHIFT_BITS); i++) {
		ip->exec_funcp = decodemep;
		ip->rawi = XICACHE_DEAD_INSTN;
		ip++;
	}
}

